package com.klun.concDesign.chapterFour.V4_4_8;

import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicReferenceArray;

import static com.sun.prism.impl.PrismSettings.debug;

public class LockFreeVector<E> {
    private int N_BUCKET = 30;
    private int FIRST_BUCKET_SIZE = 8;
    private AtomicReference<Descriptor<E>> descriptorArry;
    private final AtomicReferenceArray<AtomicReferenceArray<E>> buckets;
    int zeroNumFirst  = 30;

    public LockFreeVector() {
        buckets = new AtomicReferenceArray<AtomicReferenceArray<E>>(N_BUCKET);
        buckets.set(0,new AtomicReferenceArray<E>(FIRST_BUCKET_SIZE));
        descriptorArry = new AtomicReference<Descriptor<E>>(new Descriptor<E>(0, null));
    }

    // 核心代码
    public void push_back(E e){
        Descriptor<E> desc;
        Descriptor<E> newd;
        do{
            desc = descriptorArry.get();
            desc.completeWrite();
            // pos = 旧数组的长度(desc：这个为null啊？？) + 初始长度
            int pos = desc.size + FIRST_BUCKET_SIZE;
            // Integer.numberOfLeadingZeros ？？？ 计算位数 如果pos==0 则zeroNumpos =32；第一次不为零的位置从零开始
            int zeroNumPos = Integer.numberOfLeadingZeros(pos);
            // bucketInd:用来定位数组 AtomicReferenceArray 的类型偏移量
            int bucketInd = zeroNumFirst - zeroNumPos;
            // line 11 判断这个数组是否存在，如果不存在创建数组，大小为前一个数组的2倍，并把它设置到buckets中
            if(buckets.get(bucketInd) == null){
                int newLen = 2 * buckets.get(bucketInd -1).length();
                // 这个不懂？？？TODO
                if(debug){
                    System.out.println("New Length is: "+newLen);
                }
                buckets.compareAndSet(bucketInd,null,new AtomicReferenceArray<E>(newLen));
            }
            // 获得 pos 除第一位数字1 以外的其他位的数值
            // int idx = (0x800000000 >>> zeroNumPos) ^ pos;
            String a = "10000000000000000000000000000000";
            int b = Integer.parseInt(a, 2);
            int idx = ( b >>> zeroNumPos) ^ pos; // zeroNumPos 左边有多少位零 ，pos元素的个数
            newd = new Descriptor<E>(desc.size + 1,new Descriptor.WriteDescriptor<E>(
                    buckets.get(bucketInd),idx,null,e
            ));
        }while (!descriptorArry.compareAndSet(desc,newd));
        descriptorArry.get().completeWrite();
    }

    public E get(int index){
        int pos = index + FIRST_BUCKET_SIZE;
        int zeroNumPos = Integer.numberOfLeadingZeros(pos);
        int bucketInd  = zeroNumFirst - zeroNumPos;
        String a = "10000000000000000000000000000000";
        int b = Integer.parseInt(a, 2);
        int idx = ( b >>> zeroNumPos) ^ pos;
        return buckets.get(bucketInd).get(idx);
    }

    public static void main(String[] args) {
        String a = "01000000000000000000000000000000";
        int i = Integer.parseInt(a, 2);
        System.out.println(i);
        int zeroNumPos = Integer.numberOfLeadingZeros(i);
        System.out.println("zeroNumPos: "+zeroNumPos);
    }
}
